<?php

class address_slot extends entity
{
    public $structs = [
        'rule' => '',
        'number' => '',
        'estate_id' => '',
        'is_contain_output_address_unit' => '',
    ];

    public static $entity_display_name = '地址槽';
    public static $entity_description = '地址槽';

    const IS_CONTAIN_OUTPUT_ADDRESS_UNIT_YES = 1;
    const IS_CONTAIN_OUTPUT_ADDRESS_UNIT_NO = 0;

    const IS_CONTAIN_OUTPUT_ADDRESS_UNIT_MAPS = [
        self::IS_CONTAIN_OUTPUT_ADDRESS_UNIT_YES => '是',
        self::IS_CONTAIN_OUTPUT_ADDRESS_UNIT_NO => '否',
    ];

    public static $struct_formats = [
        'is_contain_output_address_unit' => self::IS_CONTAIN_OUTPUT_ADDRESS_UNIT_MAPS,
    ];

    public static $struct_format_descriptions = [
        'is_contain_output_address_unit' => '',
    ];

    public static $null_entity_mock_attributes = [
        'rule' => '未配置地址槽',
    ];

    public function __construct()
    {/*{{{*/
        $this->belongs_to('estate');
        $this->has_many('address_unit_turns', 'address_unit_turn');
    }/*}}}*/

    public static function create()
    {/*{{{*/
        return parent::init();
    }/*}}}*/

    public function delete_relation_entities()
    {/*{{{*/
        relationship_batch_load($this->address_unit_turns, 'address_unit_values');

        foreach ($this->address_unit_turns as $address_unit_turn) {

            $address_unit_turn->delete();

            foreach ($address_unit_turn->address_unit_values as $address_unit_value) {

                $address_unit_value->delete();
            }
        }
    }/*}}}*/

    public function prepare_set_rule($rule)
    {/*{{{*/
        if ($rule === $this->rule) {
            return $rule;
        }

        $address_unit_infos = explode('*', $rule);

        unset($address_unit_infos[0]);

        $this->delete_relation_entities();

        $address_units = [];

        foreach ($address_unit_infos as $number => $name) {

            if ($name) {

                $address_unit = dao('address_unit')->find_by_name($name);

                if ($address_unit->is_null()) {

                    $address_unit = address_unit::create();
                    $address_unit->name = $name;
                }

                $address_unit_turn = address_unit_turn::create();
                $address_unit_turn->address_slot = $this;
                $address_unit_turn->address_unit = $address_unit;
                $address_unit_turn->number = $number;

                $address_units[$address_unit->id] = $address_unit;
            }
        }

        $this->compare_with_output_address_unit($address_units);

        return $rule;
    }/*}}}*/

    public function get_is_contain_output_address_unit_description()
    {/*{{{*/
        return self::IS_CONTAIN_OUTPUT_ADDRESS_UNIT_MAPS[$this->is_contain_output_address_unit];
    }/*}}}*/

    private function compare_with_output_address_unit($address_units)
    {/*{{{*/
        otherwise($address_units, '异常使用场景 '.__FUNCTION__);

        $estate = $this->estate;

        $output_address_slot = $estate->output_address_slot;

        if ($output_address_slot->is_null()) {

            return $this->is_contain_output_address_unit = self::IS_CONTAIN_OUTPUT_ADDRESS_UNIT_NO;
        } 

        $output_address_units = relationship_batch_load($output_address_slot, 'address_unit_turns.address_unit');

        if ($output_address_units == array_intersect($output_address_units, $address_units)) {

            return $this->is_contain_output_address_unit = self::IS_CONTAIN_OUTPUT_ADDRESS_UNIT_YES;
        } else {

            return $this->is_contain_output_address_unit = self::IS_CONTAIN_OUTPUT_ADDRESS_UNIT_NO;
        }
    }/*}}}*/

    public function set_is_contain_output_address_unit()
    {/*{{{*/
        $address_units = relationship_batch_load($this->address_unit_turns, 'address_unit');

        return $this->compare_with_output_address_unit($address_units);
    }/*}}}*/

    public function is_contain_output_address_unit_yes()
    {/*{{{*/
        return $this->is_contain_output_address_unit == self::IS_CONTAIN_OUTPUT_ADDRESS_UNIT_YES;
    }/*}}}*/

    public function is_contain_output_address_unit_no()
    {/*{{{*/
        return $this->is_contain_output_address_unit == self::IS_CONTAIN_OUTPUT_ADDRESS_UNIT_NO;
    }/*}}}*/

    public function match_address($address)
    {/*{{{*/
        $reg = '/^'.str_replace('\*', '([^\/]+?)', preg_quote($this->rule, '/')).'$/';

        preg_match_all($reg, $address, $matches);

        $unit_infos = [];

        if ($matched = !empty($matches[0])) {

            unset($matches[0]);

            foreach ($this->address_unit_turns as $address_unit_turn) {

                $address_unit = $address_unit_turn->address_unit;

                $unit_infos[$address_unit->id] = [
                    'unit' => $address_unit->name,
                    'value' => $matches[$address_unit_turn->number][0],
                    'string' => $matches[$address_unit_turn->number][0].$address_unit->name,
                ];
            }
        }

        return [$matched, $unit_infos];
    }/*}}}*/

    public function get_formated_address_string($unit_infos)
    {/*{{{*/
        $formated_address_string = '';

        $is_output_address_slot = $this->estate->is_output_address_slot($this);

        $is_auto_manage_value = $this->estate->is_auto_manage_value;

        $before_address_unit_value = null;

        foreach ($this->address_unit_turns as $address_unit_turn) {

            $address_unit = $address_unit_turn->address_unit;

            $formated_address_string .= $unit_infos[$address_unit->id]['string'] ?? '';

            if ($is_output_address_slot && $is_auto_manage_value) {

                $value = $unit_infos[$address_unit->id]['value'];

                $address_unit_value = dao('address_unit_value')->find_by_address_unit_turn_and_value($address_unit_turn, $value);

                if ($address_unit_value->is_null()) {

                    $address_unit_value = address_unit_value::create();
                    $address_unit_value->address_unit_turn = $address_unit_turn;
                    $address_unit_value->value = $value;
                    $address_unit_value->set_status_init();

                    if (not_null($before_address_unit_value)) {

                        $address_unit_value->before_address_unit_value = $before_address_unit_value;
                    }
                }

                $before_address_unit_value = $address_unit_value;
            }
        }

        return $formated_address_string;
    }/*}}}*/
}
